// microc.cpp : définit le point d'entrée pour l'application console.
//

#include "stdafx.h"

#include "declaration.h"
#include "interpreteur.h"
#include "econ.h"
#include "nativeFunction.h"
#include "defs.h"
#include <vector>

map<string, Var_T> Fonction::glob;
map<string, Fonction*> Fonction::func;
vector<Programme> progs;

int __declspec( dllexport ) prechargerProgramme(string path) {
	list<list<string> > splitted;

	fstream fichierInterpreter(path, fstream::in);
	if(!fichierInterpreter.is_open()) {
		die("Error: Unable to open file for interpreting.");
	}
	string ligne;
	while (!fichierInterpreter.eof()) {
		getline(fichierInterpreter, ligne);
		if (ligne != "")
			splitted.push_back(split(ligne.c_str()));
	}

	fichierInterpreter.close();

	list<list<token> > toks;
	for(list<list<string> >::iterator i = splitted.begin() ; i != splitted.end() ; i++) {	
		list<list<token> > t = tokenize(*i);
		toks.insert(toks.end(), t.begin(), t.end());
	}

	list<Instruction*> instrs = abstraire(toks);
	Programme exec = construireFonctions(instrs);
	interpreterGlobal(exec.codeGlobal.corps);
	progs.push_back(exec);
	return progs.size() - 1;
}

Var_T __declspec( dllexport ) executerProgramme(int handle) {
	if(handle >= progs.size()) {
		die("Error: Invalid handle for program execution.");
	}
	
	Programme &exec = progs[handle];
	Fonction::func = exec.funcs;
	Var_T ret;
	
	if(exec.funcs.find("main") != exec.funcs.end()) {
		ret = exec.funcs["main"]->interpreter();
	} else {
		die("Error: main function is not defined.");
	}

	return ret;
}

void __declspec( dllexport ) supprimerProgramme(int handle) {
	
	if(handle >= progs.size()) {
		die("Error: Invalid handle for program deletion.");
	}

	for(map<string, Fonction*>::iterator it = progs[handle].funcs.begin() ; it != progs[handle].funcs.end() ; it++) {
		delete it->second;
	}

	vector<Programme>::iterator it = progs.begin() + (handle);
	progs.erase(it);
}

Var_T __declspec( dllexport ) executerCallback(int handle, string nomFunc, list<Var_T> *params) {
	
	if(handle >= progs.size()) {
		die("Error: Invalid handle for callback execution.");
	}
	
	Fonction::func = progs[handle].funcs;
	Var_T ret;
	Call back; //heh
	back.qui = nomFunc;
	
	if(params != NULL) {
		for(list<Var_T>::iterator i = params->begin() ; i != params->end() ; i++) {
			Types newParam;
			newParam.typeActuel == i->type;
			if(i->type == TYPE_NUM) {
				newParam.math.dejaCalculer = true;
				newParam.math.valeur = i->val.ld;
			} else if(i->type == TYPE_BOOL) {
				newParam.condition.valeur.cond = i->val.b;
				newParam.condition.droite = NULL;
				newParam.condition.gauche = NULL;
			}

			back.params.push_back(newParam);
		}
	}
	
	if(Fonction::func.find(nomFunc) != Fonction::func.end()) {
		ret = back.evaluer(NULL, &Fonction::glob).var;
	} else {
		die("Error: callback undefined.");
	}

	return ret;
}

bool __declspec( dllexport ) registerNativeFunction(int handle, string name, string format, Var_T (*ptr)(list<Var_T> params)) {
	
	if(handle >= progs.size()) {
		die("Error: Invalid handle for callback execution.");
	}
	
	nativeFunction *f = new nativeFunction();
	if(!f)
		return false;

	f->func = ptr;

	for(const char *c = format.c_str() ; *c != '\0' ; c++) {
		Var_T paramAct;
		bool arrayModifier = false;

		if(*c == 'a') {
			arrayModifier = true;
		} else if(*c == 'b') {
			if(arrayModifier) {
				paramAct.type = TYPE_BOOL_ARRAY;
				arrayModifier = false;
			} else {
				paramAct.type = TYPE_BOOL;
			}

			f->params.push_back(paramAct);
		} else if(*c == 'n') {
			if(arrayModifier) {
				paramAct.type = TYPE_NUM_ARRAY;
				arrayModifier = false;
			} else {
				paramAct.type = TYPE_NUM;
			}
			f->params.push_back(paramAct);
		} else {
			die("Error: incorrect format in callback registration.");
		}
	}

	progs[handle].funcs[name] = f;

	return true;
}

void die(char *err) {
	cout << err << endl;
	system("pause");
	exit(1);
}

/* 
int main() {
	int h = prechargerProgramme("C:/prog.mcc");
	executerProgramme(h);
	cout << "Hourra!" << endl; 
	system("pause");
	supprimerProgramme(h);
	return 0;
} */